import java.util.Stack;

/*
 * REmember: dummy head array
 */
public class StackTupleHandler {

	int order;
	String pieces[];
	
	/*
	 * when the whole tuple is nil, 
	 * is false when on of the elements of tuple are nil
	 */
	boolean isNil = false;

	public StackTupleHandler(int order) {
		super();
		this.order = order;
		pieces = new String[order + 1];
	}
	
	public static void main(String[] args) {
		StackTupleHandler tup = new StackTupleHandler("<nil>");
		StackTupleHandler tup2 = new StackTupleHandler("$$tau::2::<INT:2>::<nil>::$$");
		StackTupleHandler tup3 = new StackTupleHandler("$$tau::1::<INT:2>::$$");
		StackTupleHandler tup4 = new StackTupleHandler("$$tau::4::<INT:2>::<INT:3>::$$tau::2::<INT:89>::<nil>::$$::<INT:1000>::$$");
		//StackTupleHandler tup2 = new StackTupleHandler("$$tau::2::$$tau::2::<INT:89>::$$tau::1::<INT:12>::$$::$$::<INT:1000>::$$");
		//tup2.aug("<STR:'fishy'>");
		System.out.println(tup.print());
		System.out.println(tup2.print());
		System.out.println(tup3.print());
		System.out.println(tup4.print());
		//tup.aug("<nil>");
		System.out.println(tup.print());
		tup.aug("<INT:2>");
		tup.aug("<STR:'2'>");
		tup.aug(tup2.print());
		System.out.println(tup.print());
		
	}
	
	public String print(){
		
		if (isNil){
			return "<nil>";
		}
		
		/*if ((pieces.length - 1) == 1){
			int i = pieces.length - 1;
			if (pieces[i].substring(0, 7).equals("$$tau::")){
				StackTupleHandler tuple = new StackTupleHandler(pieces[i]);
				return tuple.print() ;
			}else{
				return printPrimitive(pieces[i]);
			}
		}*/
		
		String returnVal = "(";
		for(int i = 1 ; i < (pieces.length-1) ; i++){
			if (pieces[i].substring(0, 7).equals("$$tau::")){
				StackTupleHandler tuple = new StackTupleHandler(pieces[i]);
				returnVal += tuple.print() + ", ";
			}else{
				returnVal += printPrimitive(pieces[i]) + ", ";
			}
		}
		int i = pieces.length - 1;
		if ( !pieces[i].equals("<nil>") && pieces[i].substring(0, 7).equals("$$tau::")){
			StackTupleHandler tuple = new StackTupleHandler(pieces[i]);
			returnVal += tuple.print() ;
		}else{
			returnVal += printPrimitive(pieces[i]);
		}
		returnVal += ")";
		return returnVal;
	}
	
	String printPrimitive(String param1){
		
		if (param1.equals("<nil>")){
			return "<nil>";
		}
		
		param1 = param1.replace('<', ' ');
		param1 = param1.replace('>', ' ');
		param1 = param1.replace('\'', ' ');
		param1 = param1.trim();
		if (param1.contains(":")){
			return param1.split(":")[1].trim();
		}else{
			return param1;
		}
	
	}
	
	/*
	 * $$tau::#::..:: ... ::$$
	 */
	public StackTupleHandler(String stackElement) {
		if (stackElement.equals("<nil>")){
			isNil = true;
			return;
		}else if (!stackElement.substring(0,7).equals("$$tau::")){
			System.out.println("element not a tuple");
			System.exit(0);
		}
		
		String tokens[] = stackElement.split("::");
		order = Integer.parseInt(tokens[1]);
		pieces = new String[order+1];
		
		int tokenPointer = 2;
		String temp;
		for(int pieceCounter = 1 ; pieceCounter <= order ; pieceCounter++){
			temp = tokens[tokenPointer];
			if (temp.equals("$$tau")){
				StoreTemp store = getTupleFromPieces(tokens, tokenPointer); 
				pieces[pieceCounter] = store.str;
				tokenPointer = store.tokenPointer;
			}else{
				pieces[pieceCounter] = temp;
				tokenPointer++;
			}
		}
	}
	
	private StoreTemp getTupleFromPieces(String[] tokens, int tokenPointer) {
		assert(tokens[tokenPointer].equals("$$tau")):"get tuple from pieces : problem with algo";
		String currentPiece = tokens[tokenPointer] + "::" ;// which "$$tau";
		tokenPointer++;
		while(true){
			if (tokens[tokenPointer].equals("$$tau")){
				StoreTemp store = getTupleFromPieces(tokens, tokenPointer); 
				currentPiece += store.str + "::";
				tokenPointer = store.tokenPointer;
			}else if (tokens[tokenPointer].equals("$$")){
				currentPiece += "$$";
				tokenPointer++;
				return new StoreTemp(currentPiece, tokenPointer);
			}else{
				currentPiece += tokens[tokenPointer] + "::";
				tokenPointer++;
			}
		}
	}
	
	public void setPiece(int i, String str){
		if (i == 0 | i > (order+1)){
			System.out.println("Tuple: Cannot set a piece outside the order of the tuple");
			System.exit(0);
		}
		pieces[i] = str;
	}
	
	public String getPiece(int i){
		return pieces[i];
	}
	
	/*
	 * Constructor makes sure that the obect created is a tuple or a nil
	 * but nothing else
	 */
	public void aug(String newPiece){
		if (isNil){
			createFromAug(newPiece);
			return;
		}
		
		order++;
		String newTuple[] = new String[order+1];
		for(int i = 1 ; i < (order+1-1) ; i++)
		{
			newTuple[i] = pieces[i];
		}
		newTuple[order+1-1] = newPiece;
		
		pieces = newTuple;
	}
	
	public void createFromAug(String stackElement){
		order = 1;
		pieces = new String[2];
		pieces[1] = stackElement;
		isNil = false;
	}
	
	@Override
	public String toString() {
		if (isNil){
			return "<nil>";
		}
		String returnVal = "$$tau::"+order;
		for(int i = 1 ; i < (order+1) ; i++)
		{
			returnVal += "::" + pieces[i];
		}
		returnVal += "::$$";
		return returnVal;
	}
	
	class StoreTemp{
		String str;
		int tokenPointer;
		
		public StoreTemp(String str, int i) {
			super();
			this.str = str;
			this.tokenPointer = i;
		}
	}
}
